/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.core.convert.support;

import java.nio.charset.Charset;
import java.util.Currency;
import java.util.Locale;
import java.util.UUID;

import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.lang.Nullable;

/**
 * 对一系列的converter进行注册
 *
 * 核心功能 (Core Function):
 * - 提供一个默认的类型转换服务，预先注册了常用的 Converter（标量、集合、枚举、Locale、Charset、UUID 等）
 * - 是 Spring 类型系统的“默认实现”，可被直接使用，也可作为扩展基础。
 *
 * 主要逻辑流程 (Main Flow):
 * 1. 构造函数调用 {@link #addDefaultConverters(ConverterRegistry)}，注册所有默认的转换器。
 * 2. 提供 {@link #getSharedInstance()} 方法，实现懒加载的单例共享实例（线程安全，双重检查锁）。
 * 3. 通过 {@link #addDefaultConverters(ConverterRegistry)}、{@link #addCollectionConverters(ConverterRegistry)}、
 *    {@link #addScalarConverters(ConverterRegistry)} 将 Converter 分组注册到注册表。
 *
 * 在 Spring 框架中的作用 (Role in Spring):
 * - Spring MVC、数据绑定、配置文件解析（如 @Value 注解）都会依赖 ConversionService 做类型转换。
 * - DefaultConversionService 提供“开箱即用”的默认实现，避免每次都手工注册 Converter。
 * - 前置调用方：如 Spring 容器初始化、DataBinder、EnvironmentPropertyResolver。
 * - 后置调用方：各种具体的转换逻辑，例如 String → Enum、String → Locale。
 *
 * 使用到的设计模式与架构思想 (Design Patterns):
 * 1. **工厂模式 (Factory Method)**：通过 {@link org.springframework.core.convert.converter.ConverterFactory}
 *    动态创建不同类型的 Converter。
 * 2. **策略模式 (Strategy Pattern)**：不同类型转换逻辑由不同 {@link org.springframework.core.convert.converter.Converter} 实现，
 *    运行时根据上下文选择。
 * 3. **单例模式 (Singleton)**：{@link #getSharedInstance()} 提供懒加载的共享实例。
 * 4. **组合模式 (Composite)**：多个 Converter 注册到统一的 ConversionService 中。
 *
 * 关联接口 (Related Interfaces):
 * - {@link org.springframework.core.convert.converter.Converter}：定义单一源类型 → 目标类型的转换。
 * - {@link org.springframework.core.convert.converter.ConverterFactory}：定义“同一源类型 → 多个目标子类型”的转换（如 String → Enum）。
 * - {@link org.springframework.core.convert.converter.GenericConverter}：支持多对多复杂类型转换（如 Collection → Collection），
 *   可利用 {@link org.springframework.core.convert.TypeDescriptor} 解析泛型和注解。
 *
 * A specialization of {@link GenericConversionService} configured by default
 * with converters appropriate for most environments.
 *
 * <p>Designed for direct instantiation but also exposes the static
 * {@link #addDefaultConverters(ConverterRegistry)} utility method for ad-hoc
 * use against any {@code ConverterRegistry} instance.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @since 3.1
 */
public class DefaultConversionService extends GenericConversionService {

	/**
	 * sharedInstance 是一个懒加载的单例（volatile + 双重检查锁保证线程安全）
	 */
	@Nullable
	private static volatile DefaultConversionService sharedInstance;


	/**
	 * Create a new {@code DefaultConversionService} with the set of
	 * {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}.
	 * <p>
	 * 创建一个新的 DefaultConversionService，并自动注册所有默认的 Converter。
	 * - 入口：构造方法
	 * - 调用链：构造函数 → addDefaultConverters
	 * - 作用：保证实例化后即可使用，用户无需手工配置。
	 */
	public DefaultConversionService() {
		addDefaultConverters(this);
	}


	/**
	 * Return a shared default {@code ConversionService} instance,
	 * lazily building it once needed.
	 *
	 * 返回一个共享的默认 {@code ConversionService} 实例，采用懒加载的方式在首次需要时才创建。
	 *
	 * <p><b>NOTE:</b> We highly recommend constructing individual
	 * {@code ConversionService} instances for customization purposes.
	 *
	 * 注意：强烈建议用户自行创建独立的 ConversionService 实例以便自定义转换规则。
	 *
	 * This accessor is only meant as a fallback for code paths which
	 * need simple type coercion but cannot access a longer-lived
	 * {@code ConversionService} instance any other way.
	 *
	 * 此方法仅作为兜底方案，用于一些只需简单类型转换、但无法获取已有 ConversionService 实例的场景。
	 *
	 * 核心功能 (Core Function):
	 * - 提供一个线程安全的、全局共享的 ConversionService 实例。
	 * - 避免重复创建 DefaultConversionService，提高性能。
	 *
	 * 主要逻辑流程 (Main Flow):
	 * 1. 读取共享实例到局部变量 cs。
	 * 2. 第一次检查 (if cs == null)：若已存在实例，直接返回，避免加锁。
	 * 3. 如果为 null，则进入 synchronized 块（类级别锁，确保多线程安全）。
	 * 4. 第二次检查 (if cs == null)：防止多个线程同时通过第一次检查后重复创建。
	 * 5. 如果确实没有实例，则 new 一个 DefaultConversionService，并赋值给 sharedInstance。
	 * 6. 返回共享实例。
	 *
	 * 设计模式与思想 (Design Patterns):
	 * - **单例模式 (Singleton Pattern)**：保证全局只有一个共享实例。
	 * - **双重检查锁 (Double-Checked Locking, DCL)**：第一次检查提升性能，第二次检查保证线程安全。
	 * - **懒加载 (Lazy Initialization)**：只有在第一次调用时才会创建实例。
	 *
	 * @return the shared {@code ConversionService} instance (never {@code null})
	 *         返回共享的 ConversionService 实例（保证非空）
	 * @since 4.3.5
	 */
	public static ConversionService getSharedInstance() {
		// 第一次检查，避免每次调用都加锁，提高性能
		DefaultConversionService cs = sharedInstance;
		if (cs == null) {
			// 类级别锁，保证多线程环境下只有一个线程能进入初始化过程
			synchronized (DefaultConversionService.class) {
				// 第二次检查，防止多个线程同时通过第一次检查后，重复创建对象
				cs = sharedInstance;
				if (cs == null) {
					// 真正创建实例，并注册默认的 Converter
					cs = new DefaultConversionService();
					sharedInstance = cs;
				}
			}
		}
		// 返回共享实例
		return cs;
	}

	/**
	 * Add converters appropriate for most environments.
	 * 向 ConverterRegistry 注册大多数环境下需要的默认 Converter。
	 * <p>
	 * 逻辑流程:
	 * 1. 调用 addScalarConverters 注册标量类型转换（String ↔ Number、Enum、Locale 等）
	 * 2. 调用 addCollectionConverters 注册集合和数组转换
	 * 3. 注册与时区、时间、Optional 等相关的 Converter
	 *
	 * @param converterRegistry the registry of converters to add to
	 *                          (must also be castable to ConversionService, e.g. being a {@link ConfigurableConversionService})
	 * @throws ClassCastException if the given ConverterRegistry could not be cast to a ConversionService
	 */
	public static void addDefaultConverters(ConverterRegistry converterRegistry) {
		addScalarConverters(converterRegistry);
		addCollectionConverters(converterRegistry);

		converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
		converterRegistry.addConverter(new StringToTimeZoneConverter());
		converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
		converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());

		converterRegistry.addConverter(new ObjectToObjectConverter());
		converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
		converterRegistry.addConverter(new FallbackObjectToStringConverter());
		converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
	}

	/**
	 * Add common collection converters.
	 * 注册集合、数组、流之间的常见转换器。
	 * <p>
	 * 逻辑流程:
	 * 1. 数组 ↔ 集合
	 * 2. 数组 ↔ 数组
	 * 3. 集合 ↔ 集合
	 * 4. Map ↔ Map
	 * 5. 数组/集合 ↔ String
	 * 6. 数组/集合 ↔ Object
	 * 7. 集合 ↔ Stream
	 *
	 * @param converterRegistry the registry of converters to add to
	 *                          (must also be castable to ConversionService, e.g. being a {@link ConfigurableConversionService})
	 * @throws ClassCastException if the given ConverterRegistry could not be cast to a ConversionService
	 * @since 4.2.3
	 */
	public static void addCollectionConverters(ConverterRegistry converterRegistry) {
		ConversionService conversionService = (ConversionService) converterRegistry;

		converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
		converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));

		converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
		converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
		converterRegistry.addConverter(new MapToMapConverter(conversionService));

		converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
		converterRegistry.addConverter(new StringToArrayConverter(conversionService));

		converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
		converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));

		converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
		converterRegistry.addConverter(new StringToCollectionConverter(conversionService));

		converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
		converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));

		converterRegistry.addConverter(new StreamConverter(conversionService));
	}

	/**
	 * 注册常用的标量转换器（Scalar converters）
	 * <p>
	 * 包括：
	 * - String ↔ Number/Boolean/Character/Enum
	 * - Number ↔ Character
	 * - Enum ↔ Integer/String
	 * - String ↔ Locale/Charset/Currency/UUID/Properties
	 */
	private static void addScalarConverters(ConverterRegistry converterRegistry) {
		converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());

		converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
		converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToCharacterConverter());
		converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new NumberToCharacterConverter());
		converterRegistry.addConverterFactory(new CharacterToNumberFactory());

		converterRegistry.addConverter(new StringToBooleanConverter());
		converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
		converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));

		converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());
		converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));

		converterRegistry.addConverter(new StringToLocaleConverter());
		converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToCharsetConverter());
		converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToCurrencyConverter());
		converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());

		converterRegistry.addConverter(new StringToPropertiesConverter());
		converterRegistry.addConverter(new PropertiesToStringConverter());

		converterRegistry.addConverter(new StringToUUIDConverter());
		converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
	}

}
